using System;
using System.Globalization;
using NUnit.Framework;
using ValidationFramework.Extensions;

namespace ValidationFramework.Tests
{
    [TestFixture]
    public class RangeByteRuleAttributeTest
    {

        [Test]
        public void RunForAllNumberTypes()
        {
            CallAttributeTester<byte>();
            CallAttributeTester<int>();
            CallAttributeTester<long>();
            CallAttributeTester<double>();
            CallAttributeTester<float>();
            CallAttributeTester<short>();
            CheckValues<byte>();
            CheckValues<int>();
            CheckValues<long>();
            CheckValues<double>();
            CheckValues<float>(); 
            CheckValues<short>();
        }

        private static RangeRuleAttribute GetRuleAttribute<T>(T minimum, T maximum)
        {
            var attributeTypeName = string.Format("ValidationFramework.Range{0}RuleAttribute,ValidationFramework", TypeHelper.GetTypeFromKeyName<T>());
            var attributeType = Type.GetType(attributeTypeName);
            var constructorInfo = attributeType.GetPublicInstanceConstructor( typeof(T), typeof(T) );
            return (RangeRuleAttribute)constructorInfo.Invoke(new object[]{ minimum, maximum});
        }

   
        public void CheckValues<T>() where T : IComparable<T>
        {
            var expectedMinimum = (T)Convert.ChangeType(2, typeof(T), CultureInfo.InvariantCulture);
            var expectedMaximum = (T)Convert.ChangeType(4, typeof(T), CultureInfo.InvariantCulture);
            var ruleAttribute = GetRuleAttribute(expectedMinimum, expectedMaximum);
            Assert.AreEqual(expectedMinimum, TypeHelper.GetPropertyValue<T>(ruleAttribute,"Minimum"));
            Assert.AreEqual(expectedMaximum, TypeHelper.GetPropertyValue<T>(ruleAttribute,"Maximum"));

            var propertyRule = TypeHelper.CreatePropertyRule<RangeRule<T>>(ruleAttribute, new MockPropertyDescriptor<T>("foo"));
            var parameterRule = TypeHelper.CreateParameterRule<RangeRule<T>>(ruleAttribute, new MockParameterDescriptor<T>("foo"));

            Assert.AreEqual(expectedMinimum, propertyRule.Minimum);
            Assert.AreEqual(expectedMaximum, propertyRule.Maximum);

            Assert.AreEqual(expectedMinimum, parameterRule.Minimum);
            Assert.AreEqual(expectedMaximum, parameterRule.Maximum);

        }

        public void CallAttributeTester<T>() where T : IComparable<T>
        {
            var expectedMinimum = (T)Convert.ChangeType(2, typeof(T), CultureInfo.InvariantCulture);
            var expectedMaximum = (T)Convert.ChangeType(4, typeof(T), CultureInfo.InvariantCulture);
            AttributeTester.CheckDefaultValues<T>(GetRuleAttribute(expectedMinimum, expectedMaximum), true, true);
            AttributeTester.CheckNonDefaultValues<T>(GetRuleAttribute(expectedMinimum, expectedMaximum), true, true);
        }


    }
}